package withLamportClock;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.*;
import java.util.ArrayList;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;



public class Helper implements Runnable{
	
	private int id; //id of the philosopher
	private static final int REQV = 21;
	private static final int REQP = 22;
	private static final int VOP  = 23;
	private static final int POP  = 24;
	private static final int ACK  = 25;	
	private int lc = 1; //Logical Clock
	
	private ArrayList<Message> queueList;
	private int first;
	private int last;
	private int s;
	
	private int portaLocal;
	private ArrayList<Integer> outrosHelpers;
	private int portaPhilosopho;
	
	static Logger logger = Logger.getLogger(Helper.class);	
		
	public Helper(int philoID) {
		super();
		this.id = philoID;
		this.queueList = new ArrayList<Message>();
		this.first = 0;
		this.last = 0;
		this.portaLocal = 6000 + this.id;
		this.portaPhilosopho = 8000 + this.id;
		this.outrosHelpers = new ArrayList<Integer>();
		for(int i=0;i<5;i++){
			this.outrosHelpers.add(this.portaLocal + i);
		}		
		BasicConfigurator.configure(); 
        logger.setLevel(Level.INFO);         
	}

	@Override
	public void run() {
		this.lc = 1;
		this.s = 0;
		Message message;
		
		while(true){
			
			message = null;
			while(message == null){
				message = NetFunctions.receiveSemop(this.portaLocal);
			}
			this.lc = Math.max(message.getTimeStamp(), this.lc + 1);
			this.lc++;	
			
			if(message.getMsg() == REQP){
				Message popMsg = new Message(this.portaLocal,POP,this.lc);
				NetFunctions.broadCastSemop(this.outrosHelpers, popMsg);
				this.lc++;
			} else {
				if(message.getMsg() == REQV){
					Message vopMsg = new Message(this.portaLocal,VOP,this.lc);
					NetFunctions.broadCastSemop(this.outrosHelpers, vopMsg);
					this.lc++;					
				} else {
					if((message.getMsg() == POP)||(message.getMsg()==VOP)){
						this.queueList.add(message);
						Message ackMsg = new Message(this.portaLocal,ACK,this.lc);
						NetFunctions.broadCastSemop(this.outrosHelpers, ackMsg);
						this.lc++;
					} else { //TODO: check this, isso esta muito obscuro!
						//message.getMsg() == ACK !!
						
						//percorre os vops
						Message iterator;
						for(int l=0; l < this.queueList.size(); l++){
							 iterator = this.queueList.get(l);
							 if( (iterator.getPorta() == message.getPorta()) && iterator.getMsg() == VOP){
								 	 this.queueList.remove(l);
									 this.s++;
									 break;
								 }
						}
						
						//percorre os pops
						for(int l=0; l < this.queueList.size(); l++){
							 iterator = this.queueList.get(l);
							 if( (iterator.getPorta() == message.getPorta()) && iterator.getMsg() == POP){
								 	 this.queueList.remove(l);
									 this.s--;
									 if(iterator.getPorta() == this.portaLocal){
										 NetFunctions.sendGo(this.portaPhilosopho, this.lc);
									 }									 
									 break;
								 }
						}						
					}
				}
			}
			
			
		}
	}
}
